﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Timers;
using VMDS.Business.Entities;
using VMDS.Business.Processes;
using VMDS.Data;
using VMDS.Services.Contracts;
using VMDS.Settings;
using Timer = System.Timers.Timer;

namespace VMDS.Services.MainService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.

    class RegPc
    {
        public ClientPC PC { get; set; }
        public DateTime LastConnect { get; set; }
    }

    
    public class MainService : IMainServiceContract
    {
        public string Share =ServerConfiguration.Share;
        public string UpdPath = ServerConfiguration.UpdatePath;
        #region IMainServiceContract Members

        private static SqlDataGateway _GW;
        public static SqlDataGateway GW { get { return _GW ?? new SqlDataGateway(); }
        }

        

        public List<Task> GetAllTasks()
        {
            try
            {
                //var GW = new SqlDataGateway();
                return GW.GetTasks();
            }
            catch (Exception e)
            {
                Logger.WriteLog(e.ToString(),true,true);
                throw;
            }
            
        }

        public void CompleteTask(int Id)
        {
            try
            {
                var t = GW.GetTask(Id);
                t.Completed = true;
                GW.UpdateTask(t);
            }
            catch (Exception e)
            {
                Logger.WriteLog(e.ToString(), true, true);
                throw;
            }

        }

        public bool TestRights()
        {
            return VMDS.Security.VmdsRoleProvider.IsManager;
        }

        static List<RegPc> OnlinePCs { get; set; }
        static List<RegPc> UnknownOnlinePCs { get; set; }
        static Timer timer;
        public List<Task> GetMyTasks(string MyName)
        {
            try
            {
                ClientPC pc = GetPcByName(MyName);
                if (timer == null)
                {
                    timer = new Timer() {Interval = 10000};
                    timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                    timer.Enabled = true;
                }

                if (pc == null)
                {
                    if (UnknownOnlinePCs == null) UnknownOnlinePCs = new List<RegPc>();
                    if (!UnknownOnlinePCs.Any(x => x.PC.Name == MyName))
                        UnknownOnlinePCs.Add(new RegPc()
                                                 {
                                                     LastConnect = DateTime.Now,
                                                     PC = new ClientPC() {Name = MyName}
                                                 });
                    AddPCs(new List<ClientPC>(){new ClientPC(){Name = MyName}});
                    return new List<Task>();
                }
                if (OnlinePCs == null) OnlinePCs = new List<RegPc>();
                if (!OnlinePCs.Any(x => x.PC.Id == pc.Id))
                    OnlinePCs.Add(new RegPc()
                                      {
                                          LastConnect = DateTime.Now,
                                          PC = pc
                                      });
                return GetAllTasks().Where(x => (x.ClientPCId == pc.Id) && (!x.Completed)).ToList();
            }
            catch (Exception e)
            {
                Logger.WriteLog(e.ToString(), true, true);
                throw;
            }
            
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                if (UnknownOnlinePCs == null) return;
                if (OnlinePCs == null) return;
                var all = new List<RegPc>(UnknownOnlinePCs);
                foreach (var todelete in from regPc in all
                                         let timeout = DateTime.Now - regPc.LastConnect
                                         where timeout.Minutes > 1
                                         select UnknownOnlinePCs.SingleOrDefault(x => x.PC.Name == regPc.PC.Name)
                                         into todelete
                                         where todelete != null
                                         select todelete)
                {
                    UnknownOnlinePCs.Remove(todelete);
                }
                all = new List<RegPc>(OnlinePCs);
                foreach (var todelete in from regPc in all
                                         let timeout = DateTime.Now - regPc.LastConnect
                                         where timeout.Seconds > 59
                                         select OnlinePCs.SingleOrDefault(x => x.PC.Name == regPc.PC.Name)
                                         into todelete
                                         where todelete != null
                                         select todelete)
                {
                    OnlinePCs.Remove(todelete);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
            
        }


        public List<VM> GetVMs()
        {
            try
            {
                return GW.GetVMs();
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
            
        }

        
        public List<OS> GetOSs()
        {
            try
            {
                return GW.GetOSs();
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
            
        }

        public string GetShareUNC()
        {
            try
            {
                return Share;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
            
        }

        public string GetUpdateUNC()
        {
            return UpdPath;
        }

        public void AddOs(string name)
        {
            try
            {
               
                GW.AddOS(new OS {Name = name, Version = 0});
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public void DeleteOS(int OsId)
        {
            try
            {
               
                var os = GW.GetOSs().SingleOrDefault(x => x.Id == OsId);
                if (os == null) throw new Exception("Os not found");
                try
                {
                    Directory.Delete(Share + "\\OS\\" + os.Name, true);
                }
                catch (Exception exception)
                {
                    throw new Exception("Cannot delete " + os.Name + " from share");
                }
                GW.DeleteOS(os);
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }


        }

        public void AddTasks(List<Task> list)
        {
            try
            {
               
                foreach (var task in list)
                {
                    GW.AddTask(task);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }



        public void DeleteTask(Task t)
        {
            try
            {
               
                GW.DeleteTask(t);
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public int AddVm(VM vm)
        {
            try
            {
               
                return GW.AddVM(vm);
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public void UpdateVm(VM vm)
        {
            try
            {
                GW.UpdateVM(vm);
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public void DeleteVM(int VmId)
        {
            try
            {
                var vm = GW.GetVMs().SingleOrDefault(x => x.Id == VmId);
                if (vm == null) throw new Exception("Vm Not Found");
                
                foreach (var task in GW.GetTasks())
                {
                    if (task.VMId == vm.Id) GW.DeleteTask(task);
                }
                GW.DeleteVM(vm);
                try
                {
                    var path = Share + "\\VM\\" + vm.Name;
                    if (Directory.Exists(path)) Directory.Delete(path, true);
                }
                catch (Exception exception)
                {
                    //throw new Exception("Cannot delete " + vm.Name + " from share");
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }

        }

        public List<ClientPC> GetPCs()
        {
            try
            {
               
                return GW.GetClientPCs();
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public void AddPC(ClientPC pc)
        {
            throw new NotImplementedException();
        }

        public void RemovePC(ClientPC pc)
        {
            try
            {
                
                GW.DeleteClientPC(pc);
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public void AddPCs(List<ClientPC> pcs)
        {
            try
            {
                
                List<ClientPC> dblist = GW.GetClientPCs();
                foreach (ClientPC pc in pcs)
                {
                    if (dblist.Any(x => x.Name.ToLower() == pc.Name.ToLower())) continue;
                    GW.AddClientPC(pc);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public List<ClientPC> GetOnlinePCs()
        {
            try
            {
                return OnlinePCs.Select(pc => pc.PC).ToList();
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }

        public List<string> GetUnknownPCs()
        {
            try
            {
                if (UnknownOnlinePCs!=null)
                return UnknownOnlinePCs.Select(pc => pc.PC.Name).ToList();
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
            return new List<string>();
        }

        #endregion

        private ClientPC GetPcByName(string name)
        {
            try
            {
                return GW.GetClientPCs().SingleOrDefault(x => x.Name.ToLower() == name.ToLower());
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex.ToString(), true, true);
                throw;
            }
        }
    }
}